/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.evaluation.onsite.assets;

import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationConclusion;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationItem;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationResult;
import cn.ac.nercis.pes.common.constant.knowledge.LayerTarget;
import cn.ac.nercis.pes.common.constant.manage.EvaluationEntryMode;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.common.utils.ConvertUtils;
import cn.ac.nercis.pes.community.component.controls.MenuListCell;
import cn.ac.nercis.pes.community.component.dialog.*;
import cn.ac.nercis.pes.community.component.photo.ThumbnailControl;
import cn.ac.nercis.pes.community.constant.AppConstants;
import cn.ac.nercis.pes.community.controller.evaluation.onsite.BaseEvaluationController;
import cn.ac.nercis.pes.community.controller.evaluation.onsite.ChooseExpectedResultController;
import cn.ac.nercis.pes.community.controller.evaluation.onsite.EvalController;
import cn.ac.nercis.pes.community.controller.evaluation.photo.PhotoSelectController;
import cn.ac.nercis.pes.community.model.vo.MenuVO;
import cn.ac.nercis.pes.community.service.SysConfigService;
import cn.ac.nercis.pes.community.support.controls.JFXPopup;
import cn.ac.nercis.pes.community.utils.ControlUtils;
import cn.ac.nercis.pes.community.utils.*;
import cn.ac.nercis.pes.community.views.evaluation.onsite.ChooseExpectedResultView;
import cn.ac.nercis.pes.community.views.evaluation.onsite.EvalView;
import cn.ac.nercis.pes.community.views.evaluation.photo.PhotoSelectView;
import cn.ac.nercis.pes.model.dto.evaluation.onsite.EvaluationRecordDTO;
import cn.ac.nercis.pes.model.dto.knowledge.KmExpectedResultDTO;
import cn.ac.nercis.pes.model.dto.knowledge.KmSimpleTargetDTO;
import cn.ac.nercis.pes.service.evaluation.EvaluationRecordService;
import cn.ac.nercis.pes.service.knowledge.KmExpectedResultService;
import cn.ac.nercis.pes.service.utils.CalculateUtils;
import cn.ac.nercis.pes.service.utils.FileManage;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 系统资产测评管理控制器（技术类型）
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class AssetTechnologyEvalController extends BaseEvaluationController {

    protected final static String D_RESULT_TITLE = "密码使用有效性";
    protected final static String UNIFIED_TITLE = "结果记录";

    @FXML
    private VBox workspaceBox;
    @FXML
    private HBox evalTargetBox;
    @FXML
    private Label assetNameLbl;
    @FXML
    private Label currentTargetLbl;

    @FXML
    private StackPane unitTargetPane;
    @FXML
    private HBox judgeOptionBox;
    @FXML
    private HBox judgeAOption;
    @FXML
    private HBox judgeKOption;
    @FXML
    private ComboBox<String> dResultCombo;
    @FXML
    private ComboBox<String> aResultCombo;
    @FXML
    private ComboBox<String> kResultCombo;
    @FXML
    private Label notApplyResult;
    @FXML
    private ListView<MenuVO> resultListView;

    @FXML
    private ListView<MenuVO> menuListView;
    @FXML
    private Button tmpSaveButton;

    @FXML
    private Button saveButton;
    @FXML
    private VBox targetDescBox;
    @FXML
    private Label evaMethodLbl;
    @FXML
    private HBox evaDescBlock;
    @FXML
    private VBox evaDescBox;
    @FXML
    private Label scoreLbl;

    @FXML
    private VBox dResultBlock;
    @FXML
    private VBox aResultBlock;
    @FXML
    private VBox kResultBlock;
    @FXML
    private VBox notApplyBlock;
    @FXML
    private FlowPane dPictureBox;
    @FXML
    private FlowPane aPictureBox;
    @FXML
    private FlowPane kPictureBox;
    @FXML
    private TextArea dContentTxt;
    @FXML
    private TextArea aContentTxt;
    @FXML
    private TextArea kContentTxt;
    @FXML
    private TextArea notApplyContentTxt;
    @FXML
    private StackPane evalDescPane;

    private final StringProperty layerTargetName = new SimpleStringProperty();
    private final ObjectProperty<EvaluationEntryMode> entryMode = new SimpleObjectProperty<>();
    private final BooleanBinding dakMode;
    private final EvaluationRecordService evaluationRecordService;
    private final KmExpectedResultService expectedResultService;

    private String currentSystemId;
    private MenuVO currentAsset;
    private MenuVO groupAsset;
    private KmSimpleTargetDTO currentLayerTarget;
    private MenuVO currentUnitTarget;
    private EvaluationRecordDTO currentEvaluationRecord;
    private StackPane page;
    private PageDialog pageDialog;
    private JFXPopup unitTargetPopup;

    public AssetTechnologyEvalController() {
        this.evaluationRecordService = SpringUtils.getBean(EvaluationRecordService.class);
        this.expectedResultService = SpringUtils.getBean(KmExpectedResultService.class);
        this.dakMode = Bindings.createBooleanBinding(this::isDakMode, entryMode);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        currentTargetLbl.setGraphic(IconUtils.getGlyph("expand-menu-icon", "expand-menu-icon"));
        saveButton.setGraphic(IconUtils.getGlyph("save-button-icon", "btn-icon"));
        tmpSaveButton.setGraphic(IconUtils.getGlyph("temp-save-button-icon", "btn-icon"));
        tmpSaveButton.disableProperty().bind(dataSaving);
        saveButton.disableProperty().bind(dataSaving);

        dResultCombo.getItems().addAll(EvaluationResult.MATCH.getName(), EvaluationResult.NOT_MATCH.getName(), EvaluationResult.NOT_APPLICABLE.getName());
        aResultCombo.getItems().addAll(EvaluationResult.MATCH.getName(),EvaluationResult.NOT_MATCH.getName());
        kResultCombo.getItems().addAll(EvaluationResult.MATCH.getName(),EvaluationResult.NOT_MATCH.getName());
        bindVisibleAndManage(judgeOptionBox,judgeAOption,judgeKOption,notApplyResult,dResultBlock,aResultBlock,kResultBlock,notApplyBlock);

        initMenus();
//        initTextEditor(dContentTxt,aContentTxt,kContentTxt,notApplyContentTxt);
        //附加复制功能
        ControlUtils.appendCopy(assetNameLbl,this::onCopySuccessTip);
        ControlUtils.appendCopy(evaMethodLbl,this::onCopySuccessTip);
        ControlUtils.appendCopy(evaDescBox,this::onCopySuccessTip);

        realTimeSaveManager.listenerTextChange(dContentTxt, aContentTxt, kContentTxt, notApplyContentTxt);
        GuiStore.applyQuickSave(this.workspaceBox, this::onGlobalSave);
    }

    public void initializeData(String systemId, MenuVO currentAsset, MenuVO groupAsset, KmSimpleTargetDTO layerTarget){
        this.currentSystemId = systemId;
        this.currentAsset = currentAsset;
        this.groupAsset = groupAsset;
        this.currentLayerTarget = layerTarget;
        this.realTimeSaveManager.setEnable(false);
        LogUtils.info(log, "初始化技术类指标测评对象内容...");
        layerTargetName.setValue(layerTarget.getName());
        var evalView = AppStore.getEvaluationView(this.currentSystemId, EvalView.class);
        if(evalView.getController() instanceof EvalController controller){
            this.page = controller.getPage();
        }
        if(Objects.isNull(this.groupAsset)){
            ControlUtils.setLabelTextByLimit(assetNameLbl, currentAsset.getToolTip(),AppConstants.MAX_SHOW_TEXT_LENGTH);
        }else if(StringUtils.equals(groupAsset.getToolTip(),currentAsset.getToolTip())){
            ControlUtils.setLabelTextByLimit(assetNameLbl, currentAsset.getToolTip(),AppConstants.MAX_SHOW_TEXT_LENGTH);
        }else{
            ControlUtils.setLabelTextByLimit(assetNameLbl, String.format("%s/%s",groupAsset.getToolTip(),currentAsset.getToolTip()),AppConstants.MAX_SHOW_TEXT_LENGTH);
        }
        entryMode.set(SpringUtils.getBean(SysConfigService.class).getEvaluationEntryMode());
        this.loadMenuData();
    }

    public StringProperty layerTargetNameProperty(){
        return layerTargetName;
    }
    public String getLayerTargetName(){
        return layerTargetName.getValue();
    }

    @FXML
    public void onTmpSave(){
        LogUtils.info(log, "执行暂存操作...");
        saveEvaluationRecord(false);
    }

    @FXML
    public void onFinishSave(){
        LogUtils.info(log, "执行保存操作...");
        saveEvaluationRecord(true);
    }

    @Override
    public void onGlobalSave() {
        LogUtils.info(log, "执行快捷保存操作...");
        saveEvaluationRecord(false, false);
    }

    @Override
    public void realTimeSave(){
        LogUtils.info(log, "执行即时保存操作...");
        this.saveEvaluationRecord(true,false);
    }

    public String getDResultTitle() {
        return isDakMode() ? D_RESULT_TITLE : UNIFIED_TITLE;
    }

    @FXML
    public void onUnitTargetPopup(){
        unitTargetPopup.show(evalTargetBox,JFXPopup.PopupVPosition.TOP,JFXPopup.PopupHPosition.LEFT,
                0,currentTargetLbl.getHeight()+10);
    }

    @FXML
    public void onShowDescClick(){
        LogUtils.info(log, "查看测评说明操作...");
        this.showAssetEvalMethod(this.currentSystemId,this.currentAsset.getCode(),this.currentLayerTarget, this.currentUnitTarget.getCode(),
                ()->loadEvaluationRecord(this.currentUnitTarget));
    }



    @FXML
    public void onDResultClick(){
        checkExpectedResult(EvaluationItem.D,dResultCombo);
    }

    @FXML
    public void onAResultClick(){
        checkExpectedResult(EvaluationItem.A,aResultCombo);
    }

    @FXML
    public void onKResultClick(){
        checkExpectedResult(EvaluationItem.K,kResultCombo);
    }

    @FXML
    public void onDResultChange(){
        if(!realTimeSaveManager.getEnable()){
            return;
        }
        LogUtils.info(log, "执行D结论变更操作...");
        EvaluationResult dResult = Optional.ofNullable(dResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        judgeAOption.setVisible(dResult == EvaluationResult.MATCH);
        judgeKOption.setVisible(dResult == EvaluationResult.MATCH);
        currentEvaluationRecord.setDResult(dResult);
        CalculateUtils.calculateTechnologyScore(currentEvaluationRecord);
        scoreLbl.setText(ConvertUtils.scoreToString(currentEvaluationRecord.getScore()));
        realTimeSaveManager.onChange();
    }

    @FXML
    public void onAResultChange(){
        if(!realTimeSaveManager.getEnable()){
            return;
        }
        LogUtils.info(log, "执行A结论变更操作...");
        EvaluationResult aResult = Optional.ofNullable(aResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        currentEvaluationRecord.setAResult(aResult);
        CalculateUtils.calculateTechnologyScore(currentEvaluationRecord);
        scoreLbl.setText(ConvertUtils.scoreToString(currentEvaluationRecord.getScore()));
        realTimeSaveManager.onChange();
    }

    @FXML
    public void onKResultChange(){
        if(!realTimeSaveManager.getEnable()){
            return;
        }
        LogUtils.info(log, "执行K结论变更操作...");
        EvaluationResult kResult = Optional.ofNullable(kResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        currentEvaluationRecord.setKResult(kResult);
        CalculateUtils.calculateTechnologyScore(currentEvaluationRecord);
        scoreLbl.setText(ConvertUtils.scoreToString(currentEvaluationRecord.getScore()));
        realTimeSaveManager.onChange();
    }

    @FXML
    public void onAddDFileClick(){
        LogUtils.info(log, "执行添加D证据文件操作...");
        var selectView = AppStore.getEvaluationView(this.currentSystemId, PhotoSelectView.class);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-edit-icon")
                .withTitle("选择密码使用安全（D）证据文件")
                .withContent(Objects.requireNonNull(selectView).load())
                .withOwner(AppStore.getCurrentSystem(this.currentSystemId).getEvaluationStage())
                .build();
        pageDialog.setYesText("确定");
        pageDialog.setNoText("取消");
        if(selectView.getController() instanceof PhotoSelectController controller){
            controller.initializeData(this.currentSystemId, LayerTarget.fromName(currentLayerTarget.getName()));
        }
        pageDialog.show(this::saveDPhotoFile);
    }

    @FXML
    public void onAddAFileClick(){
        LogUtils.info(log, "执行添加A证据文件操作...");
        var selectView = AppStore.getEvaluationView(this.currentSystemId,PhotoSelectView.class);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-edit-icon")
                .withTitle("选择密码算法/技术合规性（A）证据文件")
                .withContent(Objects.requireNonNull(selectView).load())
                .withOwner(AppStore.getCurrentSystem(this.currentSystemId).getEvaluationStage())
                .build();
        pageDialog.setYesText("确定");
        pageDialog.setNoText("取消");
        if(selectView.getController() instanceof PhotoSelectController controller){
            controller.initializeData(this.currentSystemId,LayerTarget.fromName(currentLayerTarget.getName()));
        }
        pageDialog.show(this::saveAPhotoFile);
    }

    @FXML
    public void onAddKFileClick(){
        LogUtils.info(log, "执行添加K证据文件操作...");
        var selectView = AppStore.getEvaluationView(this.currentSystemId,PhotoSelectView.class);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-edit-icon")
                .withTitle("选择密钥管理安全（K）证据文件")
                .withContent(Objects.requireNonNull(selectView).load())
                .withOwner(AppStore.getCurrentSystem(this.currentSystemId).getEvaluationStage())
                .build();
        pageDialog.setYesText("确定");
        pageDialog.setNoText("取消");
        if(selectView.getController() instanceof PhotoSelectController controller){
            controller.initializeData(this.currentSystemId,LayerTarget.fromName(currentLayerTarget.getName()));
        }
        pageDialog.show(this::saveKPhotoFile);
    }

    public ObjectProperty<EvaluationEntryMode> entryModeProperty() {
        return entryMode;
    }

    public EvaluationEntryMode getEntryMode() {
        return entryMode.get();
    }

    public BooleanBinding dakModeProperty() {
        return dakMode;
    }

    public boolean isDakMode() {
        return getEntryMode() == EvaluationEntryMode.DAK_MODE;
    }

    protected void checkExpectedResult(EvaluationItem evalItem, ComboBox<String> resultCombo) {
        EvaluationConclusion evalConclusion = Optional.ofNullable(resultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationConclusion::fromName)
                .orElse(EvaluationConclusion.DEFAULT);
        if (evalConclusion == EvaluationConclusion.DEFAULT) {
            return;
        }
        LogUtils.info(log, "获取预期结果信息...");
        LogUtils.record(log, "请求数据，layerTarget：{},unitTarget:{},assetId:{}", currentLayerTarget.getName(),
                currentUnitTarget.getTitle(), currentAsset.getCode());
        CompletableFuture.supplyAsync(() -> expectedResultService.findExpectedResults(currentLayerTarget.getName(),
                        currentUnitTarget.getTitle(), currentAsset.getCode(), evalItem, evalConclusion))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        if (CollectionUtils.isNotEmpty(res.getData())) {
                            selectedExpectedResult(res.getData(), evalItem, evalConclusion);
                        }
                    } else {
                        AppUtils.showMessageDialog(res.getMsg(),MessageType.WARN,this.page);
                    }
                }))
                .exceptionally((ex) -> {
                    this.dataSaving.setValue(false);
                    log.error("获取预期结果信息出错!", ex);
                    return null;
                });
    }

    private void selectedExpectedResult(List<KmExpectedResultDTO> expectedResults, EvaluationItem evalItem, EvaluationConclusion evalConclusion) {
        var resultView = AppStore.getEvaluationView(this.currentSystemId, ChooseExpectedResultView.class);
        pageDialog = PageDialog.builder()
                .withIcon("dialog-edit-icon")
                .withTitle("选择预期结果信息")
                .withContent(Objects.requireNonNull(resultView).load())
                .withOwner(AppStore.getCurrentSystem(this.currentSystemId).getEvaluationStage())
                .build();
        pageDialog.setYesText("确定");
        pageDialog.setNoText("取消");
        if(resultView.getController() instanceof ChooseExpectedResultController controller){
            controller.initializeData(this.currentSystemId,this.currentAsset.getToolTip(),expectedResults);
        }
        pageDialog.show(() -> applyExpectedResult(evalItem, evalConclusion));
    }

    private void applyExpectedResult(EvaluationItem evalItem, EvaluationConclusion evalConclusion) {
        var resultView = AppStore.getEvaluationView(this.currentSystemId,ChooseExpectedResultView.class);
        String result = "";
        if(resultView.getController() instanceof ChooseExpectedResultController controller){
            result = controller.selectedExpectedResult();
        }
        if (StringUtils.isBlank(result)) {
            AppUtils.showMessageDialog("请选择使用的预期结果！",MessageType.WARN,this.page);
            return;
        }
        if (evalConclusion == EvaluationConclusion.NOT_APPLICABLE) {
            notApplyContentTxt.setText(result);
        } else {
            if (evalItem == EvaluationItem.A) {
                aContentTxt.setText(result);
            } else if (evalItem == EvaluationItem.K) {
                kContentTxt.setText(result);
            } else {
                dContentTxt.setText(result);
            }
        }
        pageDialog.close();
    }


    private void saveDPhotoFile(){
        var selectView = AppStore.getEvaluationView(this.currentSystemId,PhotoSelectView.class);
        List<File> addFiles = new ArrayList<>();
        if(selectView.getController() instanceof PhotoSelectController controller){
            addFiles.addAll(controller.selectedPhotoFile());
        }
        if(CollectionUtils.isEmpty(addFiles)){
            this.pageDialog.close();
            return;
        }
        List<File> photoFiles = this.dPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .toList();
        addFiles.stream()
                .filter(file->photoFiles.stream().noneMatch(pf->StringUtils.equals(file.getPath(),pf.getPath())))
                .forEach(this::addDPhotoImage);
        String fileNames = this.dPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .map(File::getName)
                .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        this.currentEvaluationRecord.setDFiles(fileNames);
        this.realTimeSaveManager.onChange();
        this.pageDialog.close();
    }
    private void saveAPhotoFile(){
        var selectView = AppStore.getEvaluationView(this.currentSystemId,PhotoSelectView.class);
        List<File> addFiles = new ArrayList<>();
        if(selectView.getController() instanceof PhotoSelectController controller){
            addFiles.addAll(controller.selectedPhotoFile());
        }
        List<File> photoFiles = this.aPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .toList();
        addFiles.stream()
                .filter(file->photoFiles.stream().noneMatch(pf->StringUtils.equals(file.getPath(),pf.getPath())))
                .forEach(this::addAPhotoImage);
        String fileNames = this.aPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .map(File::getName)
                .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        this.currentEvaluationRecord.setAFiles(fileNames);
        this.realTimeSaveManager.onChange();
        this.pageDialog.close();
    }
    private void saveKPhotoFile(){
        var selectView = AppStore.getEvaluationView(this.currentSystemId,PhotoSelectView.class);
        List<File> addFiles = new ArrayList<>();
        if(selectView.getController() instanceof PhotoSelectController controller){
            addFiles.addAll(controller.selectedPhotoFile());
        }
        if(CollectionUtils.isEmpty(addFiles)){
            this.pageDialog.close();
            return;
        }
        List<File> photoFiles = this.kPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .toList();
        addFiles.stream()
                .filter(file->photoFiles.stream().noneMatch(pf->StringUtils.equals(file.getPath(),pf.getPath())))
                .forEach(this::addKPhotoImage);
        String fileNames = this.kPictureBox.getChildren()
                .stream()
                .filter(n->n instanceof ThumbnailControl)
                .map(n->(ThumbnailControl)n)
                .map(ThumbnailControl::getPictureFile)
                .map(File::getName)
                .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        this.currentEvaluationRecord.setKFiles(fileNames);
        this.realTimeSaveManager.onChange();
        this.pageDialog.close();
    }

    private void saveEvaluationRecord(boolean finishSave) {
        this.saveEvaluationRecord(false,finishSave);
    }

    private void saveEvaluationRecord(boolean realTime,boolean finishSave) {
        collectEvaluationRecordData();
        if (validContent()) {
            checkEvaluationConclusion(realTime,finishSave);
        }
    }

    protected void checkEvaluationConclusion(boolean realTime,boolean finishSave) {
        if (StringUtils.isEmpty(currentEvaluationRecord.getId())) {
            saveData(realTime,finishSave);
            return;
        }
        dataSaving.setValue(true);
        LogUtils.info(log, "测评结果变更前检查...");
        LogUtils.record(log, "请求数据:{}", currentEvaluationRecord);
        CompletableFuture.supplyAsync(() -> evaluationRecordService.checkEvaluationConclusion(currentEvaluationRecord))
                .thenAccept(res -> Platform.runLater(() -> {
                    dataSaving.setValue(false);
                    if (res.isSuccess()) {
                        saveData(realTime,finishSave);
                    } else {
                        AlertDialog alertDialog = AlertDialog.builder()
                                .withMode(AlertMode.CONFIRM)
                                .withType(AlertType.WARN)
                                .withTitle("操作提示")
                                .withContent(res.getMsg())
                                .withContainer(Objects.requireNonNull(this.page))
                                .build();
                        alertDialog.show((confirm) -> {
                            if (confirm) {
                                saveData(realTime,finishSave);
                            } else {
                                loadEvaluationRecord(currentUnitTarget);
                            }
                        });
                    }
                }))
                .exceptionally((ex) -> {
                    this.dataSaving.setValue(false);
                    log.error("测评结果变更前检查出错!", ex);
                    return null;
                });
    }

    private void saveData(boolean realTime,boolean finishSave) {
        dataSaving.setValue(true);
        LogUtils.info(log, "保存测评记录信息...");
        LogUtils.record(log, "请求数据:{}", currentEvaluationRecord);
        CompletableFuture.supplyAsync(() -> evaluationRecordService.saveAssetEvaluationRecord(currentEvaluationRecord))
                .thenAccept(res -> Platform.runLater(() -> {
                    dataSaving.setValue(false);
                    if (res.isSuccess()) {
                        //重新加载内容数据
                        initEvaluationRecord(res.getData());
                        this.setRecordFinishState(finishSave);
                        ControlUtils.refreshScoreInfo(this.currentSystemId);
                        if(!realTime){
                            AppUtils.showMessageDialog("保存成功",MessageType.SUCCESS,this.page);
                        }
                        this.checkUnitNotApply();
                    } else {
                        if(realTime){
                            log.error("即时保存测评记录信息失败：{}",res.getMsg());
                        }else{
                            AppUtils.showMessageDialog(res.getMsg(),MessageType.FAIL,this.page);
                        }
                    }
                }))
                .exceptionally((ex) -> {
                    this.dataSaving.setValue(false);
                    log.error("保存测评记录信息出错!", ex);
                    return null;
                });
    }

    private void checkUnitNotApply(){
        LogUtils.info(log, "检查当前技术类型单元指标下的现场记录是否全为不适用...");
        CompletableFuture.supplyAsync(() -> evaluationRecordService.checkUnitTargetNotApply(currentSystemId,currentEvaluationRecord.getUnitTargetId()))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (!res.isSuccess()) {
                        AlertDialog.builder()
                                .withContainer(this.page)
                                .withTitle("系统提示")
                                .withContent(res.getMsg())
                                .withMode(AlertMode.ALERT)
                                .withType(AlertType.WARN)
                                .build().show();
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("检查当前技术类型单元指标下的现场记录是否全为不适用出错!", ex);
                    return null;
                });
    }

    private void setRecordFinishState(boolean finishSave){
        FinishState state = finishSave ? FinishState.FINISH : FinishState.INCOMPLETE;
        CompletableFuture.supplyAsync(()->evaluationRecordService.setRecordFinishState(currentEvaluationRecord.getId(),state))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        refreshFinishState(state);
                    } else {
                        MessageDialog.builder()
                                .withContainer(this.page)
                                .withType(MessageType.FAIL).withMessage(res.getMsg())
                                .build().show();
                    }
                }))
                .exceptionally((ex) -> {
                    this.dataSaving.setValue(false);
                    log.error("设置测评进度信息出错!", ex);
                    return null;
                });
    }

    private void refreshFinishState(FinishState state){
        currentUnitTarget.setIcon(ControlUtils.finishStateToIcon(state));
        currentUnitTarget.setState(state);
        menuListView.refresh();
        var evalView = AppStore.getEvaluationView(this.currentSystemId,EvalView.class);
        if(evalView.getController() instanceof EvalController controller){
            controller.refreshAssetNode(Objects.nonNull(groupAsset)?groupAsset.getCode():currentAsset.getCode());
        }
    }

    private void collectEvaluationRecordData(){
        if(!currentEvaluationRecord.getIsApply()){
            currentEvaluationRecord.setContent(notApplyContentTxt.getText());
            return;
        }
        EvaluationResult dResult = Optional.ofNullable(dResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        EvaluationResult aResult = Optional.ofNullable(aResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        EvaluationResult kResult = Optional.ofNullable(kResultCombo.getSelectionModel().getSelectedItem())
                .map(EvaluationResult::fromName)
                .orElse(EvaluationResult.DEFAULT);
        currentEvaluationRecord.setDResult(dResult);
        currentEvaluationRecord.setDContent(dContentTxt.getText());
        currentEvaluationRecord.setAResult(aResult);
        currentEvaluationRecord.setAContent(aContentTxt.getText());
        currentEvaluationRecord.setKResult(kResult);
        currentEvaluationRecord.setKContent(kContentTxt.getText());
    }

    private boolean validContent() {
        if (StringUtils.length(currentEvaluationRecord.getDContent()) > AppConstants.MAX_RECORD_CONTENT_LENGTH) {
            AppUtils.showMessageDialog("密码使用安全（D）内容描述不能超出2000个字！",MessageType.WARN,this.page);
            return false;
        }
        if (StringUtils.length(currentEvaluationRecord.getAContent()) > AppConstants.MAX_RECORD_CONTENT_LENGTH) {
            AppUtils.showMessageDialog("密码使用安全（A）内容描述不能超出2000个字！",MessageType.WARN,this.page);
            return false;
        }
        if (StringUtils.length(currentEvaluationRecord.getDContent()) > AppConstants.MAX_RECORD_CONTENT_LENGTH) {
            AppUtils.showMessageDialog("密码使用安全（K）内容描述不能超出2000个字！",MessageType.WARN,this.page);
            return false;
        }
        if (StringUtils.length(currentEvaluationRecord.getContent()) > AppConstants.MAX_RECORD_CONTENT_LENGTH) {
            AppUtils.showMessageDialog("不适用内容描述不能超出2000个字！",MessageType.WARN,this.page);
            return false;
        }
        return true;
    }

    private void loadMenuData() {
        menuListView.getItems().clear();
        LogUtils.info(log, "获取系统资产关联单元指标信息...");
        LogUtils.record(log, "请求数据，systemId：{},data:{}", this.currentSystemId,
                currentAsset.getCode(), currentLayerTarget.getId());
        CompletableFuture.supplyAsync(() -> evaluationRecordService.findUnitTargetByAsset(this.currentSystemId,
                        currentAsset.getCode(), currentLayerTarget.getId()))
                .thenAccept(res -> Platform.runLater(() -> {
                    res.forEach(ute -> {
                        var item = new MenuVO(2,ute.getUnitTargetId(),ute.getUnitTargetName(),
                                ControlUtils.finishStateToIcon(ute.getFinishState()));
                        item.setState(ute.getFinishState());
                        menuListView.getItems().add(item);
                    });
                    selectedDefaultMenu();
                }))
                .exceptionally((ex) -> {
                    log.error("获取系统资产关联单元指标信息出错!", ex);
                    return null;
                });
    }

    private void selectedDefaultMenu(){
        boolean isSelected = false;
        for(MenuVO menuObj : menuListView.getItems()){
            isSelected = selectedDefaultMenu(menuObj,menuListView);
            if(isSelected){
                break;
            }
        }
        if(!isSelected){
            menuListView.getSelectionModel().select(0);
        }
    }
    private boolean selectedDefaultMenu(MenuVO menuLabel,ListView<MenuVO> menu){
        if(Objects.isNull(menuLabel) || StringUtils.equals(menuLabel.getIcon(),"finish-process-icon")){
            return false;
        }
        menu.getSelectionModel().select(menuLabel);
        return true;
    }

    private void initMenus(){
        menuListView.setCellFactory(listView -> new MenuListCell(MAX_SHOW_MENU_TEXT_LENGTH,true));
        menuListView.getSelectionModel()
                .selectedItemProperty()
                .addListener((observable, oldValue, newValue) -> {
                    if(Objects.nonNull(newValue)){
                        if(this.unitTargetPopup.isShowing()){
                            this.unitTargetPopup.hide();
                        }
                        loadEvaluationRecord(newValue);
                    }
                });
        unitTargetPopup = new JFXPopup(unitTargetPane);
        unitTargetPopup.showingProperty().addListener((observableValue, oldValue, newValue) -> {
            if(newValue){
                currentTargetLbl.setGraphic(IconUtils.getGlyph("fold-menu-icon","expand-menu-icon"));
            }else{
                currentTargetLbl.setGraphic(IconUtils.getGlyph("expand-menu-icon","expand-menu-icon"));
            }
        });

        resultListView.setCellFactory(cf->new MenuListCell());
        resultListView.getSelectionModel()
                .selectedItemProperty()
                .addListener((observable, oldValue, newValue) -> {
                    if(Objects.nonNull(newValue)){
                        loadResultContent(newValue);
                    }
                });
    }

    private void loadEvaluationRecord(MenuVO unitTargetEval) {
        this.currentUnitTarget = unitTargetEval;
        this.currentTargetLbl.setText(unitTargetEval.getTitle());
        LogUtils.info(log, "获取【技术类型】测评记录信息...");
        CompletableFuture.supplyAsync(() -> evaluationRecordService.getAssetEvaluationRecord(this.currentSystemId,
                        currentAsset.getCode(), unitTargetEval.getCode()))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        initEvaluationRecord(res.getData());
                    } else {
                        AppUtils.showMessageDialog(res.getMsg(),MessageType.FAIL,this.page);
                    }
                }))
                .exceptionally((ex) -> {
                    this.dataSaving.setValue(false);
                    log.error("获取【技术类型】测评记录信息出错!", ex);
                    LogUtils.record(log, "请求数据，systemId：{},assetId:{},unitTargetId:{}", this.currentSystemId,
                            currentAsset.getCode(), unitTargetEval.getCode());
                    return null;
                });
    }

    private void loadResultContent(MenuVO item){
        if(StringUtils.equals(item.getTitle(), EvaluationItem.D.getName())){
            changeResultTab(dResultBlock,aResultBlock,kResultBlock,notApplyBlock);
        }else if(StringUtils.equals(item.getTitle(),EvaluationItem.A.getName())){
            changeResultTab(aResultBlock,dResultBlock,kResultBlock,notApplyBlock);
        }else if(StringUtils.equals(item.getTitle(),EvaluationItem.K.getName())){
            changeResultTab(kResultBlock,dResultBlock,aResultBlock,notApplyBlock);
        }else{
            changeResultTab(notApplyBlock,dResultBlock,aResultBlock,kResultBlock);
        }
    }

    private void initEvaluationRecord(EvaluationRecordDTO evaluationRecord){
        this.realTimeSaveManager.setEnable(false);
        this.currentEvaluationRecord= evaluationRecord;
        this.setContent(targetDescBox,currentEvaluationRecord.getTargetDesc());
        this.setEvalMethod(evaMethodLbl,currentEvaluationRecord.getMethod());
        if(StringUtils.isBlank(currentEvaluationRecord.getDesc())){
            this.evaDescBox.getChildren().clear();
            this.evaDescBox.setVisible(false);
        }else{
            this.setContent(evaDescBox,currentEvaluationRecord.getDesc());
        }
        if(evaluationRecord.getIsApply()){
            changeResultTab(judgeOptionBox,notApplyResult);
            this.initResultList(evaluationRecord.getIsApply(),evaluationRecord.getDResult());
            if(Objects.isNull(evaluationRecord.getScore())){
                scoreLbl.setText(BaseConstants.EMPTY_SCORE_TAG);
            }else{
                scoreLbl.setText(String.valueOf(evaluationRecord.getScore()));
            }
            List<File> photoFiles = FileManage.findPhotoFiles(this.currentSystemId);
            this.initEvalDResult(photoFiles);
            this.initEvalAResult(photoFiles);
            this.initEvalKResult(photoFiles);
        }else{
            changeResultTab(notApplyResult,judgeOptionBox);
            this.initResultList(evaluationRecord.getIsApply(), EvaluationResult.DEFAULT);
            notApplyContentTxt.setText(evaluationRecord.getContent());
            scoreLbl.setText(BaseConstants.EMPTY_SCORE_TAG);
        }
        realTimeSaveManager.setEnable(true);
    }

    private void initEvalDResult(List<File> photoFiles){
        dResultCombo.getSelectionModel().select(currentEvaluationRecord.getDResult().getName());
        dContentTxt.setText(currentEvaluationRecord.getDContent());
        this.initEvalDResultFiles(photoFiles);
    }

    private void initEvalDResultFiles(List<File> photoFiles){
        dPictureBox.getChildren().clear();
        if(StringUtils.isBlank(currentEvaluationRecord.getDFiles())){
            return;
        }
        String[] fileNames = StringUtils.split(currentEvaluationRecord.getDFiles(),BaseConstants.MULTI_SPLIT_CHAR);
        for(String pictureName:fileNames){
            photoFiles.stream()
                    .filter(f->StringUtils.equals(f.getName(),pictureName))
                    .findFirst().ifPresent(this::addDPhotoImage);
        }
    }

    private void initEvalAResult(List<File> photoFiles){
        judgeAOption.setVisible(currentEvaluationRecord.getDResult() == EvaluationResult.MATCH);
        aResultCombo.getSelectionModel().select(currentEvaluationRecord.getAResult().getName());
        aContentTxt.setText(currentEvaluationRecord.getAContent());
        this.initEvalAResultFiles(photoFiles);
    }

    private void initEvalAResultFiles(List<File> photoFiles){
        aPictureBox.getChildren().clear();
        if(StringUtils.isBlank(currentEvaluationRecord.getAFiles())){
            return;
        }
        String[] fileNames = StringUtils.split(currentEvaluationRecord.getAFiles(),BaseConstants.MULTI_SPLIT_CHAR);
        for(String pictureName:fileNames){
            photoFiles.stream()
                    .filter(f->StringUtils.equals(f.getName(),pictureName))
                    .findFirst().ifPresent(this::addAPhotoImage);
        }
    }

    private void initEvalKResult(List<File> photoFiles){
        judgeKOption.setVisible(currentEvaluationRecord.getDResult() == EvaluationResult.MATCH);
        kResultCombo.getSelectionModel().select(currentEvaluationRecord.getKResult().getName());
        kContentTxt.setText(currentEvaluationRecord.getKContent());
        this.initEvalKResultFiles(photoFiles);
    }

    private void initEvalKResultFiles(List<File> photoFiles){
        kPictureBox.getChildren().clear();
        if(StringUtils.isBlank(currentEvaluationRecord.getKFiles())){
            return;
        }
        String[] fileNames = StringUtils.split(currentEvaluationRecord.getKFiles(),BaseConstants.MULTI_SPLIT_CHAR);
        for(String pictureName:fileNames){
            photoFiles.stream()
                    .filter(f->StringUtils.equals(f.getName(),pictureName))
                    .findFirst().ifPresent(this::addKPhotoImage);
        }
    }


    private void addDPhotoImage(File pictureFile){
        if(!pictureFile.exists()){
            return;
        }
        try{
            ThumbnailControl thumbnailControl = new ThumbnailControl(pictureFile,this.page);
            thumbnailControl.setEnableModify(false);
            thumbnailControl.setEnableSelected(false);
            thumbnailControl.setOnDeleteEvent(this::onDeleteDFileClick);
            dPictureBox.getChildren().add(thumbnailControl);
        }catch (IOException ex){
            log.error("加载密码使用安全（D）证据文件失败：",ex);
            AppUtils.showMessageDialog("载入密码使用安全（D）证据文件失败！",MessageType.FAIL,this.page);
        }
    }

    private void addAPhotoImage(File pictureFile){
        if(!pictureFile.exists()){
            return;
        }
        try{
            ThumbnailControl thumbnailControl = new ThumbnailControl(pictureFile,this.page);
            thumbnailControl.setEnableModify(false);
            thumbnailControl.setEnableSelected(false);
            thumbnailControl.setOnDeleteEvent(this::onDeleteAFileClick);
            aPictureBox.getChildren().add(thumbnailControl);
        }catch (IOException ex){
            log.error("加载密码算法/技术合规性（A）证据文件失败：",ex);
            AppUtils.showMessageDialog("载入密码算法/技术合规性（A）证据文件失败！",MessageType.FAIL,this.page);
        }
    }

    private void addKPhotoImage(File pictureFile){
        if(!pictureFile.exists()){
            return;
        }
        try{
            ThumbnailControl thumbnailControl = new ThumbnailControl(pictureFile,this.page);
            thumbnailControl.setEnableModify(false);
            thumbnailControl.setEnableSelected(false);
            thumbnailControl.setOnDeleteEvent(this::onDeleteKFileClick);
            kPictureBox.getChildren().add(thumbnailControl);
        }catch (IOException ex){
            log.error("加载密钥管理安全（K）证据文件失败：",ex);
            AppUtils.showMessageDialog("载入密钥管理安全（K）证据文件失败！",MessageType.FAIL,this.page);
        }
    }

    protected void onDeleteDFileClick(ThumbnailControl source){
        LogUtils.info(log, "执行删除D证据文件操作...");
        AlertDialog alertDialog = AlertDialog.builder()
                .withMode(AlertMode.CONFIRM)
                .withType(AlertType.WARN)
                .withTitle("删除提示")
                .withContent("是否删除当前密码使用安全（D）记录文件？")
                .withContainer(this.page)
                .build();
        alertDialog.show((confirm)->{
            if(!confirm){
                return;
            }
            this.dPictureBox.getChildren().remove(source);
            String fileNames = this.dPictureBox.getChildren()
                    .stream()
                    .filter(n->n instanceof ThumbnailControl)
                    .map(n->(ThumbnailControl)n)
                    .map(ThumbnailControl::getPictureFile)
                    .map(File::getName)
                    .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
            this.currentEvaluationRecord.setDFiles(fileNames);
            this.realTimeSaveManager.onChange();
        });
    }

    protected void onDeleteAFileClick(ThumbnailControl source){
        LogUtils.info(log, "执行删除A证据文件操作...");
        AlertDialog alertDialog = AlertDialog.builder()
                .withMode(AlertMode.CONFIRM)
                .withType(AlertType.WARN)
                .withTitle("删除提示")
                .withContent("是否删除当前密码算法/技术合规性（A）记录文件？")
                .withContainer(this.page)
                .build();
        alertDialog.show((confirm)->{
            if(!confirm){
                return;
            }
            aPictureBox.getChildren().remove(source);
            String fileNames = aPictureBox.getChildren()
                    .stream()
                    .filter(n->n instanceof ThumbnailControl)
                    .map(n->(ThumbnailControl)n)
                    .map(ThumbnailControl::getPictureFile)
                    .map(File::getName)
                    .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
            this.currentEvaluationRecord.setAFiles(fileNames);
            this.realTimeSaveManager.onChange();
        });
    }

    protected void onDeleteKFileClick(ThumbnailControl source){
        LogUtils.info(log, "执行删除K证据文件操作...");
        AlertDialog alertDialog = AlertDialog.builder()
                .withMode(AlertMode.CONFIRM)
                .withType(AlertType.WARN)
                .withTitle("删除提示")
                .withContent("是否删除当前密钥管理安全（K）记录文件？")
                .withContainer(this.page)
                .build();
        alertDialog.show((confirm)->{
            if(!confirm){
                return;
            }
            kPictureBox.getChildren().remove(source);
            String fileNames = kPictureBox.getChildren()
                    .stream()
                    .filter(n->n instanceof ThumbnailControl)
                    .map(n->(ThumbnailControl)n)
                    .map(ThumbnailControl::getPictureFile)
                    .map(File::getName)
                    .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
            this.currentEvaluationRecord.setKFiles(fileNames);
            this.realTimeSaveManager.onChange();
        });
    }

    private void initResultList(boolean isApply,EvaluationResult dResult){
        var selectIndex = resultListView.getSelectionModel().getSelectedIndex();
        resultListView.getItems().clear();
        if(isApply){
            if(dResult == EvaluationResult.MATCH){
                resultListView.getItems()
                        .addAll(new MenuVO(EvaluationItem.D.getValue(),"dResult",EvaluationItem.D.getName(),"object-eval-icon"),
                                new MenuVO(EvaluationItem.A.getValue(),"aResult",EvaluationItem.A.getName(),"object-eval-icon"),
                                new MenuVO(EvaluationItem.K.getValue(),"kResult",EvaluationItem.K.getName(),"object-eval-icon"));
            }else{
                resultListView.getItems().add(new MenuVO(EvaluationItem.D.getValue(),"dResult",EvaluationItem.D.getName(),"object-eval-icon"));
            }
        }else{
            resultListView.getItems().add(new MenuVO(4,"notApplyResult","不适用","object-eval-icon"));
        }
        if(isDakMode()){
            if(selectIndex >=0 && selectIndex < resultListView.getItems().size()){
                resultListView.getSelectionModel().select(selectIndex);
            }else{
                resultListView.getSelectionModel().select(0);
            }
        }else{
            resultListView.getSelectionModel().select(0);
        }
    }

    private void onCopySuccessTip(){
        if(Objects.nonNull(this.page)){
            AppUtils.showMessageDialog("复制成功！", MessageType.SUCCESS,this.page);
        }
    }

}